-module(agent_daemon).

-behaviour(gen_server).

%%for test
-export([test_query/0]).
-export([db_state/0]).
%% API
-export([start_link/0]).

-export([regist/1]).
-export([unregist/0]).
-export([deploy/1]).
-export([undeploy/1]).
-export([query_instance_acc/0]).
-export([query_instance_term/0]).
-include_lib("stdlib/include/qlc.hrl").
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
	 terminate/2, code_change/3]).
-include("agent.hrl").
-record(state, {container=undefined , pid = undefined }).

test_query ()->
        gen_server:call(agent_daemon, {test_query}).


db_state()->
	{mnesia_op:get_pid(agent_state),mnesia_op:get_cpu(agent_state),mnesia_op:get_container(agent_state)}.
query_instance_term()->
        gen_server:call(agent_daemon, {query_instance_term} , 10000).
query_instance_acc()->
        gen_server:call(agent_daemon, {query_instance_acc} , 10000).

regist(Container)->
        gen_server:call(agent_daemon, {regist,Container}).
        

deploy(App)->
        gen_server:call(agent_daemon, {deploy,App} , 5000).

undeploy(App)->
        gen_server:call(agent_daemon, {undeploy,App}).
unregist()->
         gen_server:call(agent_daemon, {unregist}).

%%====================================================================
%% API
%%====================================================================
%%--------------------------------------------------------------------
%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
%% Description: Starts the server
%%--------------------------------------------------------------------
start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

%%====================================================================
%% gen_server callbacks
%%====================================================================

%%--------------------------------------------------------------------
%% Function: init(Args) -> {ok, State} |
%%                         {ok, State, Timeout} |
%%                         ignore               |
%%                         {stop, Reason}
%% Description: Initiates the server
%%--------------------------------------------------------------------
init([]) ->
        error_logger:info_msg("starting agent_daemon .....~n"),
        case mnesia_op:do(qlc:q([  {X#agent_state.container,
                                       X#agent_state.pid,
                                          X#agent_state.cpu } ||
                                 X <- mnesia:table(agent_state),
                                 X#agent_state.id=:=0 ])) of
              [] ->
                         {ok,#state{}};
              [{Container,Pid,_Cpu}] ->
                        error_logger:info_msg("load agent_daemon state :~p~n",[{Container,Pid}]),
                         agent_report:regist({Container,Pid}),
                        {ok, #state{container=Container,pid=Pid}}
         end.

%%--------------------------------------------------------------------
%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
%%                                      {reply, Reply, State, Timeout} |
%%                                      {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, Reply, State} |
%%                                      {stop, Reason, State}
%% Description: Handling call messages
%%--------------------------------------------------------------------
handle_call({test_query   }, _From ,State ) ->
	{reply , State , State };

handle_call( {query_instance_term}=Msg, _From , State ) ->
        error_logger:info_msg("agent_daemon:recving a  msg:~p~n",[Msg]),  
        {reply , gen_server:call(agent_httpd_proxy,{get_stat_data,term}),State };

handle_call( {query_instance_acc}=Msg, _From , State ) ->
        error_logger:info_msg("agent_daemon:recving a  msg:~p~n",[Msg]),  
        {reply , gen_server:call(agent_httpd_proxy,{get_stat_data,total}),State };
	

handle_call({regist,Container}=Msg, {Pid,_}=_From,State ) ->
        error_logger:info_msg("agent_daemon:recving a regist msg:~p~n",[Msg]),  
        case agent_report:regist( {Container,Pid}) of
                 ok ->
                           insert_state_info(Pid, Container),
                           {reply , ok  ,  #state{ container=Container , pid=Pid} } ;
                 Any ->
                           { reply , {error , Any } , State }
        end ;


              
handle_call({deploy , App  }, _From ,State ) ->
        error_logger:info_msg("agent_daemon:recving a deploy msg:~p~n",[App]),
        { reply , do_deploy_wrapper(App,State#state.container,State#state.pid) , State };

handle_call({unregist  }=Msg, _From ,State ) ->
        error_logger:info_msg("agent_daemon:recving a unregist:~p~n",[Msg]),
        {reply ,   do_undeploy(all, State#state.container) , State };

handle_call({undeploy , all  }=Msg, _From ,State ) ->
        error_logger:info_msg("agent_daemon:recving a msg:~p~n",[Msg]),
        {reply ,   do_undeploy(all, State#state.container) , State };

handle_call({undeploy , App  }, _From ,State ) ->
        error_logger:info_msg("agent_daemon:recving a undeploy msg:~p~n",[App]),
        {reply ,   do_undeploy(App, State#state.container) , State } ;

handle_call(_Request, _From, State) ->
    Reply = ok,
    {reply, Reply, State}.

%%--------------------------------------------------------------------
%% Function: handle_cast(Msg, State) -> {noreply, State} |
%%                                      {noreply, State, Timeout} |
%%                                      {stop, Reason, State}
%% Description: Handling cast messages
%%--------------------------------------------------------------------
handle_cast({unregist}, _State)->
        supervisor:terminate_child(agent_sup, agent_report),
        supervisor:restart_child(agent_sup, agent_report),
        {noreply , #state{container=undefined} } ;
handle_cast(_Msg, State) ->
    {noreply, State}.

%%--------------------------------------------------------------------
%% Function: handle_info(Info, State) -> {noreply, State} |
%%                                       {noreply, State, Timeout} |
%%                                       {stop, Reason, State}
%% Description: Handling all non call/cast messages
%%--------------------------------------------------------------------
handle_info(_Info, State) ->
    {noreply, State}.

%%--------------------------------------------------------------------
%% Function: terminate(Reason, State) -> void()
%% Description: This function is called by a gen_server when it is about to
%% terminate. It should be the opposite of Module:init/1 and do any necessary
%% cleaning up. When it returns, the gen_server terminates with Reason.
%% The return value is ignored.
%%--------------------------------------------------------------------
terminate(_Reason, _State) ->
    ok.

%%--------------------------------------------------------------------
%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
%% Description: Convert process state when code is changed
%%--------------------------------------------------------------------
code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
do_deploy_wrapper(App,Container,Pid)->
        proc_lib:spawn( fun()-> do_deploy(App,Container,Pid) end),
        ok.

do_deploy(App,Container,Pid)->
        error_logger:info_msg("agent_daemon:execute script/deploy.sh ~n"),
        Command= io_lib:format("sh script/deploy.sh ~s ~s ~s",
                        [Container#container.home,
                                App#app.source , 
                                App#app.target]),
        error_logger:info_msg("agent_daemon:Command=~p~n",[Command]),
        case os:cmd(Command )  of
               [] ->
                        error_logger:info_msg("agent_daemon:execute script/deploy.sh  success ~n"),
                        
                        case  agent_deploy_plugin:query_scripts_by_app(App#app.name) of
                                noscripts ->
                                       ok    ;
				{"" , _ } ->
					ok   ;
                                {ADScript , _} ->
                                         os:cmd(ADScript)   
                        end,
                        
                        case   agent_f5_proxy:add_domain_mapping({App#app.domain,
                                                                      Container#container.ip , 
                                                                      Container#container.port}) of
                               ok ->
                                        mnesia_op:insert(App),
                                        error_logger:info_msg("deploy the app:~p success ,send report to the process:~p~n",[App,Pid]),
                                        gen_server:cast(Pid , { deploy_report , { ok , App}});
                               {error , Any } ->
                                  error_logger:info_msg("deploy error :  Reason=~p ~n",[Any]),
                                  gen_server:cast(Pid , { deploy_report , { error , App,Any}})
                                 
                        end;
               Reason ->
                        error_logger:info_msg("deploy error :  Reason=~p~n",[Reason]),
                        gen_server:cast(Pid , { deploy_report , { error , App,Reason}})
        end.
        
do_undeploy(all,Container)->
        mnesia_op:clear_table(app),
        case agent_f5_proxy:delete_domain_mapping(
                {all ,Container#container.ip,Container#container.port } )    of
                ok ->
                        mnesia_op:clear_table(agent_state),
                        mnesia_op:clear_table(app),
			
                        ok;
                {error , Reason } -> 
                        {error , Reason }
        end;                
do_undeploy(App,Container)->
       case  agent_f5_proxy:delete_domain_mapping(
                        {App#app.domain,Container#container.ip,Container#container.port})     of
                ok ->
                        mnesia_op:delete(App),
			case  agent_deploy_plugin:query_scripts_by_app(App#app.name) of
                                noscripts ->
                                       ok    ;
				{_ , "" } ->
					ok   ;
                                {_ , AUDScript} ->
                                         os:cmd(AUDScript)   
                        end,
                        ok;
                {error , Reason } -> 
                        {error , Reason }
        end.        
        
insert_state_info(Pid, Container) ->
		mnesia_op:insert(#agent_state{id = 0, pid=Pid, container = Container}).
        
        
        
        
        
        
        
        
        
        
        
        
